﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Reflection;
using System.ComponentModel;

namespace FrameWork.Setting
{

    /// <summary>
    /// 设定值的类型
    /// </summary>
    public enum SettingValueType
    {
        Int32,
        Int64,
        String,
        Bool
    }

    /// <summary>
    /// 为设定文件操作提供基类
    /// </summary>
    public abstract class SettingOperatorBase
    {

        #region==========属性==========

        /// <summary>
        /// 设定文件路径
        /// </summary>
        public string SettingFilePath { get; internal set; }

        #endregion

        #region========抽象函数========

        /// <summary>
        /// 写入设定
        /// </summary>
        /// <param name="SettingParent">设定父</param>
        /// <param name="SettingName">设定名</param>
        /// <param name="Value">设定值</param>
        /// <returns></returns>
        public abstract bool WriteSetting(string SettingParent, string SettingName, SettingValueType Type, object Value);
        /// <summary>
        /// 读取设定
        /// </summary>
        /// <param name="SettingParent">设定父</param>
        /// <param name="SettingName">设定名</param>
        /// <param name="DefaultValue">默认值</param>
        /// <returns>设定值</returns>
        public abstract object ReadSetting(string SettingParent, string SettingName, SettingValueType Type, object DefaultValue = null);

        #endregion

        #region========公有函数========
        /// <summary>
        /// 保存指定对象中包含的设定
        /// </summary>
        /// <param name="obj">要操作设定的对象</param>
        /// <param name="ObjType">要操作的对象对应的类型</param>
        /// <param name="IsRead">一个值，表示该操作是否为读取设定或为写入设定</param>
        /// <param name="parentName">父设定名称</param>
        /// <returns>一个值，表示是否操作成功</returns>
        public bool OperateSettingFromObject(object obj, Type ObjType, bool IsRead)
        {

            SettingParentDefineAttribute SettingParAttr = ObjType.GetCustomAttribute<SettingParentDefineAttribute>();
            if (SettingParAttr == null)
            {
                throw (new InvalidOperationException("父容器未标记SettingParentDefineAttribute特性，操作无效！"));
            }

            string SettingParentName;
            if (SettingParAttr.IsNameSetted)
            {
                SettingParentName = SettingParAttr.ParentSettingName;
            }
            else
            {
                SettingParentName = ObjType.Name;
            }
            PropertyInfo[] ObjPropertyList = ObjType.GetProperties();
            foreach (PropertyInfo ProInfo in ObjPropertyList)
            {
                SettingItemDefineAttribute SettingAttr = ProInfo.GetCustomAttribute<SettingItemDefineAttribute>();
                if (SettingAttr != null)
                {
                    string SettingName;
                    SettingValueType SettingType;
                    if (SettingAttr.IsSettingNameDefined)
                    {
                        SettingName = SettingAttr.SettingName;
                    }
                    else
                    {
                        SettingName = ProInfo.Name;
                    }
                    SettingType = SettingAttr.SettingType;
                    if (IsRead)
                    {
                        if (!ProInfo.CanWrite)
                        {
                            throw new InvalidOperationException("对属性" + ProInfo.Name + "没有写入权限，操作失败！");
                        }
                        else
                        {
                            object SettingValue = ReadSetting(SettingParentName, SettingName, SettingType, SettingAttr.DefaultValue);
                            try
                            {
                                ProInfo.SetValue(obj, SettingValue);
                            }
                            catch(Exception ex)
                            {
                                throw (ex.InnerException);
                            }
                        }
                    }
                    else
                    {
                        if (!ProInfo.CanRead)
                        {
                            throw new InvalidOperationException("对属性" + ProInfo.Name + "没有读取权限，操作失败！");
                        }
                        else
                        {
                            object SettingValue;
                            SettingValue = ProInfo.GetValue(obj);
                            WriteSetting(SettingParentName, SettingName, SettingType, SettingValue);
                        }
                    }
                }
            }
            //return OperateSettingFromObject(obj, ObjType.BaseType, IsRead, SettingParentName);
            return true;
        }
        #endregion

        #region========构造函数========
        public SettingOperatorBase(string FilePath)
        {
            SettingFilePath = FilePath;
        }
        #endregion
    }

    /// <summary>
    /// 为一个支持设定读取写入器操作的属性提供特性标记
    /// </summary>
    [AttributeUsage(AttributeTargets.Property, Inherited = false, AllowMultiple = false)]
    public sealed class SettingItemDefineAttribute : Attribute
    {

        #region========私有变量========

        internal bool IsSettingNameDefined = false;

        #endregion

        #region==========属性==========
        /// <summary>
        /// 返回此特性包含的设定名称
        /// </summary>
        public string SettingName { get; private set; }
        /// <summary>
        /// 返回此特性包含的的设定类型
        /// </summary>
        public SettingValueType SettingType { get; private set; }
        /// <summary>
        /// 返回此特性包含的设定初始值
        /// </summary>
        public object DefaultValue { get; private set; }
        #endregion

        #region========公有方法========

        /// <summary>
        /// 初始化一个新的设定标志特性
        /// </summary>
        /// <param name="SettingType">设定类型</param>
        public SettingItemDefineAttribute(SettingValueType SettingType, object DefaultValue = null, string SettingName = "")
        {
            this.SettingType = SettingType;
            this.DefaultValue = DefaultValue;

            if (SettingName == "")
                IsSettingNameDefined = false;
            else
                this.SettingName = SettingName;

        }

        #endregion
    }

    /// <summary>
    /// 为一个支持设定读取写入器操作的容器类提供特性标记
    /// </summary>
    [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
    public sealed class SettingParentDefineAttribute : Attribute
    {
        internal bool IsNameSetted = false;
        /// <summary>
        /// 取得设定父的名称
        /// </summary>
        public string ParentSettingName { get; private set; }
        /// <summary>
        /// 标志一个类为设定父容器
        /// </summary>
        public SettingParentDefineAttribute()
        {
            IsNameSetted = false;
        }
        /// <summary>
        /// 标志一个类为设定父容器并指定物理名称
        /// </summary>
        /// <param name="ParentSettingName">该设定父存储在文件中的物理名称</param>
        public SettingParentDefineAttribute(string ParentSettingName)
        {
            this.ParentSettingName = ParentSettingName;
            IsNameSetted = true;
        }

    }

}
